﻿#region 命名空间

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Sharp.Domain.Model;
using Sharp.Domain.Repositories;
using Sharp.Infrastructure;
using Sharp.Infrastructure.Data;
using Sharp.Infrastructure.Search;

#endregion

namespace Sharp.Domain.CMSBoundedContext
{
    /// <summary>
    ///     仓储基类
    /// </summary>
    /// <typeparam name="TAggregateRoot"></typeparam>
    public partial class Repository<TAggregateRoot> : IRepository<TAggregateRoot>
        where TAggregateRoot : class, IAggregateRoot
    {
        private readonly EntityFrameworkRepositoryContext _efContext;

        public Repository(IRepositoryContext context)
        {
            _efContext = context as EntityFrameworkRepositoryContext;
        }

        public IRepositoryContext Context
        {
            get { return _efContext; }
        }

        public void Add(TAggregateRoot aggregateRoot)
        {
            FixData(aggregateRoot);
            var entity = aggregateRoot as IStandardEntity;
            if (entity != null)
            {
                var info = entity;
                info.CheckInTime = DateTime.Now;
                info.CheckInUserId = ContactContext.Current.UserId;
            }
            if (aggregateRoot is IStandardState)
            {
                var info = entity as IStandardState;
                info.EntityState = EntityStateOperate.Normal;
            }
            //var entity2 = aggregateRoot as IFilter4Org;
            //if (entity != null)
            //{
            //    var info = entity2;
            //    info.OrgId = ContactContext.Current.OrgId;
            //}
            Context.RegisterNew(aggregateRoot);
        }
        public void Update(TAggregateRoot aggregateRoot)
        {
            var entity = aggregateRoot as IStandardEntity;
            if (entity != null)
            {
                var info = entity;
                info.ModifiTime = DateTime.Now;
                info.ModifiedUserId = ContactContext.Current.UserId;
            }
            _efContext.RegisterModified(aggregateRoot);
        }
        public bool Exists(Expression<Func<TAggregateRoot, bool>> predicate)
        {
            return _efContext.Context.Set<TAggregateRoot>().Any(predicate);
        }

        public void Remove(TAggregateRoot aggregateRoot)
        {
            if (aggregateRoot is IStandardState)
            {
                var info = Get(aggregateRoot.Id) as IStandardState;
                info.EntityState = EntityStateOperate.IsDeleted;
                _efContext.RegisterModified(info as TAggregateRoot);
            }
            else
            {
                _efContext.RegisterDeleted(aggregateRoot);
            }
        }
        public void Remove(IEnumerable<Guid> ids)
        {
            var infos = _efContext.Context.Set<TAggregateRoot>().Where(x => ids.Contains(x.Id)).AsEnumerable();
            if (typeof(TAggregateRoot).GetInterface("IStandardState") == null)
            {
                _efContext.Context.Set<TAggregateRoot>().RemoveRange(infos);
            }
            else
            {
                infos.ToList().ForEach(x =>
                {
                    var info = x as IStandardState;
                    info.EntityState = EntityStateOperate.IsDeleted;
                    _efContext.RegisterModified(x);
                });
            }
        }


        public virtual void Merge(TAggregateRoot persisted, TAggregateRoot current)
        {
            _efContext.ApplyCurrentValues(persisted, current);
        }

        public TAggregateRoot Get(Guid key)
        {
            return Get(x => x.Id == key, (int?)null, (string)null);
        }

        public TAggregateRoot Get(Guid key,
            params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            return Get(x => x.Id == key, null, eagerLoadingProperties);
        }

        public TAggregateRoot Get(Expression<Func<TAggregateRoot, bool>> predicate)
        {
            return Get(predicate, (int?)null, (string)null);
        }
        public TAggregateRoot Get(Expression<Func<TAggregateRoot, bool>> predicate,
                   params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            return Get(predicate, null, eagerLoadingProperties);
        }
        public TAggregateRoot Get(Expression<Func<TAggregateRoot, bool>> predicate,
            int? top = null,
            params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Where(predicate);
            if (eagerLoadingProperties != null)
            {
                foreach (var item in eagerLoadingProperties)
                {
                    query = query.Include(item);
                }
            }
            if (top != null)
            {
                query = query.Take(top.Value);
            }
            return query.FirstOrDefault();
        }
        public TAggregateRoot Get(Expression<Func<TAggregateRoot, bool>> predicate,
                   int? top = null,
                   params string[] eagerLoadingProperties)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Where(predicate);
            if (eagerLoadingProperties != null)
            {
                foreach (var item in eagerLoadingProperties.Where(x => x != null))
                {
                    query = query.Include(item);
                }
            }
            if (top != null)
            {
                query = query.Take(top.Value);
            }
            return query.FirstOrDefault();
        }

        public IList<TAggregateRoot> GetList()
        {
            return GetList(x => true, "", null, (string)null);
        }


        public IList<TAggregateRoot> GetList(Expression<Func<TAggregateRoot, bool>> predicate)
        {
            return GetList(predicate, "", null, (string)null);
        }



        public IList<TAggregateRoot> GetList(params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            return GetList(null, "", null, eagerLoadingProperties);
        }


        public IList<TAggregateRoot> GetList(Expression<Func<TAggregateRoot, bool>> predicate,
            params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            return GetList(predicate, "", null, eagerLoadingProperties);
        }
        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="sort"></param>
        /// <param name="top"></param>
        /// <param name="eagerLoadingProperties"></param>
        /// <returns></returns>
        public IList<TAggregateRoot> GetList(Expression<Func<TAggregateRoot, bool>> predicate, string sort, int? top = null, params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();
            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            query = query.FilterSassData();

            foreach (var item in eagerLoadingProperties)
            {
                query = query.Include(item);
            }
            if (!sort.IsNullOrEmpty())
            {
                query = query.OrderBy(sort);
            }
            if (top != null)
            {
                query = query.Take(top.Value);
            }

            return query.ToList();
        }
        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="sort"></param>
        /// <param name="top"></param>
        /// <param name="eagerLoadingProperties"></param>
        /// <returns></returns>
        public IList<TAggregateRoot> GetList(Expression<Func<TAggregateRoot, bool>> predicate, string sort, int? top = null, params string[] eagerLoadingProperties)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();
            if (predicate != null)
            {
                query = query.Where(predicate);
            }
            query = query.FilterSassData();
            foreach (var item in eagerLoadingProperties.Where(x => x != null))
            {
                query = query.Include(item);
            }
            if (!sort.IsNullOrEmpty())
            {
                query = query.OrderBy(sort);
            }
            if (top != null)
            {
                query = query.Take(top.Value);
            }

            return query.ToList();
        }


        #region 获取分页数据
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageNo"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public PagedResult<TAggregateRoot> Pagging(int pageNo, int pageSize)
        {
            return Pagging(pageNo, pageSize, null, "ID DESC", (Expression<Func<TAggregateRoot, dynamic>>[])null);
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageNo">分页的页码。</param>
        /// <param name="pageSize">分页的页面大小。</param>
        /// <param name="sortPredicate">排序表达式</param>
        /// <returns></returns>
        public PagedResult<TAggregateRoot> Pagging(int pageNo, int pageSize, string sortPredicate)
        {
            return Pagging(pageNo, pageSize, null, sortPredicate, (Expression<Func<TAggregateRoot, dynamic>>[])null);
        }

        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageNo">分页的页码。</param>
        /// <param name="pageSize">分页的页面大小。</param>
        /// <param name="predicate">筛选表达式</param>
        /// <param name="sortPredicate">排序表达式。</param>
        /// <returns>所有符合条件的已经排序的聚合根。</returns>
        public PagedResult<TAggregateRoot> Pagging(int pageNo, int pageSize,
             Expression<Func<TAggregateRoot, bool>> predicate,
             string sortPredicate)
        {
            return Pagging(pageNo, pageSize, predicate, sortPredicate, (Expression<Func<TAggregateRoot, dynamic>>[])null);
        }

        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pf">分页参数</param>
        /// <returns></returns>
        public PagedResult<TAggregateRoot> Pagging(PagingFeature pf)
        {
            return Pagging(pf, null, (Expression<Func<TAggregateRoot, dynamic>>[])null);
        }

        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pf"></param>
        /// <param name="predicate"></param>
        /// <param name="eagerLoadingProperties"></param>
        /// <returns></returns>
        public PagedResult<TAggregateRoot> Pagging(
            PagingFeature pf,
            Expression<Func<TAggregateRoot, bool>> predicate,
             params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            var pagepredicate = new QuerySupport<TAggregateRoot>().TobuildFilter(pf);
            if (predicate != null)
            {
                var expression = Expression.And(pagepredicate.Body, predicate.Body);
                var left = predicate.Parameters[0];
                pagepredicate = Expression.Lambda<Func<TAggregateRoot, bool>>(expression, left);
            }

            return Pagging(pf.PageNo, pf.PageSize, pagepredicate, pf.SimpleSort, eagerLoadingProperties);
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageNo">分页的页码。</param>
        /// <param name="pageSize">分页的页面大小。</param>
        /// <param name="predicate">筛选表达式</param>
        /// <param name="sortPredicate">排序表达式。</param>
        /// <param name="eagerLoadingProperties">需要进行饥饿加载的属性Lambda表达式。</param>
        /// <returns>所有符合条件的已经排序的聚合根。</returns>
        public PagedResult<TAggregateRoot> Pagging(int pageNo, int pageSize,
              Expression<Func<TAggregateRoot, bool>> predicate,
              string sortPredicate,
              params Expression<Func<TAggregateRoot, dynamic>>[] eagerLoadingProperties)
        {
            _efContext.Context.Configuration.LazyLoadingEnabled = false;
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();
            if (predicate != null)
            {
                query = query.Where(predicate);
            }
            query = query.FilterSassData();
            if (eagerLoadingProperties != null)
            {
                foreach (var item in eagerLoadingProperties)
                {
                    query = query.Include(item);
                }
            }
            if (sortPredicate.Equals("ID DESC", StringComparison.CurrentCultureIgnoreCase))
            {
                query = query.OrderByDescending(x => x.Id);
            }
            else if (sortPredicate.Equals("ID ASC", StringComparison.CurrentCultureIgnoreCase))
            {
                query = query.OrderBy(x => x.Id);
            }
            else
            {
                query = query.OrderBy(sortPredicate);
            }

            return new PagedResult<TAggregateRoot>(query, pageSize, pageNo);
        }

        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pf">分页参数</param>
        /// <param name="predicate">筛选表达式</param>
        /// <param name="sortPredicate">排序表达式。</param>
        /// <param name="eagerLoadingProperties">需要进行饥饿加载的属性Lambda表达式。</param>
        /// <returns>所有符合条件的已经排序的聚合根。</returns>
        public PagedResult<TAggregateRoot> Pagging(PagingFeature pf,
              Expression<Func<TAggregateRoot, bool>> predicate,
              string sortPredicate,
              params string[] eagerLoadingProperties)
        {
            _efContext.Context.Configuration.LazyLoadingEnabled = false;
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();
            if (predicate != null)
            {
                query = query.Where(predicate);
            }
            query = query.FilterSassData();
            if (eagerLoadingProperties != null)
            {
                foreach (var item in eagerLoadingProperties)
                {
                    query = query.Include(item);
                }
            }
            if (sortPredicate.Equals("ID DESC", StringComparison.CurrentCultureIgnoreCase))
            {
                query = query.OrderByDescending(x => x.Id);
            }
            else if (sortPredicate.Equals("ID ASC", StringComparison.CurrentCultureIgnoreCase))
            {
                query = query.OrderBy(x => x.Id);
            }
            else
            {
                query = query.OrderBy(sortPredicate);
            }

            return new PagedResult<TAggregateRoot>(query, pf.PageSize, pf.PageNo);
        }
        #endregion

        #region 统计
        public int Count()
        {
            return Count(null);
        }
        public int Count(Expression<Func<TAggregateRoot, bool>> predicate)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();
            if (predicate != null)
            {
                query = query.Where(predicate);
            }
            query = query.FilterSassData();
            return query.Count();
        }
        #endregion

        #region 去重
        /// <summary>
        /// 去重
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public IEnumerable<TAggregateRoot> Distinct(Expression<Func<TAggregateRoot, bool>> predicate)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();
            if (predicate != null)
            {
                query = query.Where(predicate);
            }
            query = query.FilterSassData();
            return query.Distinct();
        }
        #endregion

        #region 分组

        public IEnumerable<TResult> GroupBy<TKey, TResult>(
            Expression<Func<TAggregateRoot, bool>> predicate,
            Expression<Func<TAggregateRoot, TKey>> keySelector,
            Expression<Func<TKey, IEnumerable<TAggregateRoot>, TResult>> resultSelector)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter();

            if (predicate != null)
            {
                query = query.Where(predicate);
            }
            query = query.FilterSassData();
            return query.GroupBy(keySelector, resultSelector);
        }
        #endregion

        #region 修正数据
        /// <summary>
        /// 修正数据
        /// </summary>
        /// <param name="root"></param>
        private void FixData(TAggregateRoot root)
        {
            foreach (var p in root.GetType().GetProperties())
            {
                if (p.PropertyType.IsAssignableFrom(typeof(DateTime)))
                {
                    if (p.GetValue(root) == null) continue;
                    if ((DateTime)p.GetValue(root) == DateTime.MinValue)
                    {
                        p.SetValue(root, null);
                    }
                }
            }
        }

        #endregion


        #region 筛选指定数据
        /// <summary>
        /// 筛选指定数据
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="selector"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public TResult SelectFirst<TResult>(Expression<Func<TAggregateRoot, bool>> predicate, Expression<Func<TAggregateRoot, TResult>> selector, int? top = null)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter().Where(predicate);
            query = query.FilterSassData();
            if (top != null)
            {
                query = query.Take(top.Value);
            }
            return query.Select(selector).First();
        }
        /// <summary>
        /// 筛选指定数据
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="selector"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public TResult SelectFirstOrDefault<TResult>(Expression<Func<TAggregateRoot, bool>> predicate, Expression<Func<TAggregateRoot, TResult>> selector, int? top = null)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter().Where(predicate);
            query = query.FilterSassData();
            if (top != null)
            {
                query = query.Take(top.Value);
            }
            return query.Select(selector).FirstOrDefault();
        }
        /// <summary>
        /// 筛选指定数据
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="selector"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public IEnumerable<TResult> Select<TResult>(Expression<Func<TAggregateRoot, bool>> predicate, Expression<Func<TAggregateRoot, TResult>> selector, int? top = null)
        {
            var query = _efContext.Context.Set<TAggregateRoot>().Filter().Where(predicate);
            query = query.FilterSassData();
            if (top != null)
            {
                query = query.Take(top.Value);
            }
            return query.Select(selector).AsEnumerable();
        }

        #endregion

        #region 批量插入

        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="entities"></param>
        public void BulkInsertAll(string tableName,IEnumerable<TAggregateRoot> entities)
        {
            entities = entities.ToArray();
            var context = _efContext.Context;
            string connectionString = context.Database.Connection.ConnectionString;
 
           
           

            Type t = typeof(TAggregateRoot);
            var properties = t.GetProperties().Where(EventTypeFilter).ToArray();
            var table = new DataTable();

            foreach (var property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsGenericType &&
                    propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                }

                table.Columns.Add(new DataColumn(property.Name, propertyType));
            }

            foreach (var entity in entities)
            {
                var newEntity = entity as IStandardEntity;
                if (newEntity != null)
                {
                    newEntity.CheckInTime = DateTime.Now;
                    newEntity.CheckInUserId = ContactContext.Current.UserId;
                }
                if (newEntity is IStandardState)
                {
                    var info = newEntity as IStandardState;
                    info.EntityState = EntityStateOperate.Normal;
                }



                table.Rows.Add(properties.Select(
                  property => GetPropertyValue(
                  property.GetValue(newEntity, null))).ToArray());
            }

            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString))
            {
                bulkCopy.BatchSize = 100000;
                bulkCopy.BulkCopyTimeout = 60;
                bulkCopy.DestinationTableName = tableName;

                //本地列名与数据库列名建立连接
                properties.ToList().ForEach(p =>
                {
                    PropertyInfo propertyInfo = p;
                    bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
                });
                


                bulkCopy.WriteToServer(table);
            }

 
 
        }

        private bool EventTypeFilter(PropertyInfo p)
        {
            var attribute = Attribute.GetCustomAttribute(p,
                typeof(AssociationAttribute)) as AssociationAttribute;

            return attribute == null;
            //if (attribute.IsForeignKey == false) return true;
        }

        private object GetPropertyValue(object o)
        {
            if (o == null)
                return DBNull.Value;
            return o;
        }
        #endregion

    }
    /// <summary>
    /// 仓储过滤器
    /// </summary>
    internal static class RepositoryFilter
    {
        /// <summary>
        /// 过滤saas的数据
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        internal static IQueryable<TAggregateRoot> FilterSassData<TAggregateRoot>(this IQueryable<TAggregateRoot> query)
            where TAggregateRoot : class, IAggregateRoot
        {
            //if (typeof(IFilter4Org).IsAssignableFrom(typeof(TAggregateRoot)))
            //{
            //    var orgids = ServiceLocator.Instance.GetService<IUserService>().GetAuthorizedOrgIds();
            //    var left = Expression.Parameter(typeof(TAggregateRoot), "m");

            //    if (orgids == null || !orgids.Any())//如果没有配置权限，只能看自己组织的数据
            //    {
            //        Expression constant = Expression.Constant(ContactContext.Current.OrgId);
            //        Expression right = Expression.Equal(Expression.Property(left, "OrgId"), constant);

            //        query = query.Where(Expression.Lambda<Func<TAggregateRoot, bool>>(right, left));
            //    }
            //    else
            //    {
            //        Expression expression = Expression.Constant(false);
            //        foreach (var orgid in orgids)
            //        {
            //            Expression constant = Expression.Constant(orgid);
            //            var t = Expression.Property(left, "OrgId").Type;
            //            var m = t.GetMethod(t == typeof(Guid?) ? "op_Equality" : "Equal");

            //            Expression right = Expression.Equal(Expression.Property(left, "OrgId"),
            //               Expression.Convert(constant, t), false, m);

            //            expression = Expression.Or(right, expression);
            //        }
            //        query = query.Where(Expression.Lambda<Func<TAggregateRoot, bool>>(expression, left));
            //    }
            //}

            return query;
        }
    }
}